#pragma once
#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <pthread.h>
#include <string>
#include <vector>
#include <functional>
#include "Mutex.hpp"
#include "Sem.hpp"

using namespace my_sem;
using namespace my_mutex;

static const int gcap = 5;
template <typename T>
class RingQueue
{
public:
    RingQueue(int cap = gcap)
        : _rq(cap), _cap(cap), _block_sem(cap), _data_sem(0), _p_step(0), _c_step(0)
    {
    }
    ~RingQueue()
    {
    }

    void Equeue(const T &data)
    {
        _block_sem.P();
        {
            MutexGuard lockguard;
            _rq[_p_step] = data;
            ++_p_step;
            _p_step = _p_step % _cap;
        }
        _data_sem.V();
    }

    void Pop(T* out)
    {
        _data_sem.P();
        {
            MutexGuard lockguard;
            *out = _rq[_c_step];
            _c_step++;
            _c_step = _c_step % _cap;
        }
        _block_sem.V();
    }

private:
    std::vector<T> _rq;
    size_t _cap;
    // 生产者
    Sem _block_sem;
    int _p_step;
    // 消费者
    Sem _data_sem;
    int _c_step;

    // 维护多生产多消费
    Mutex _pmutex;
    Mutex _cmutex;
};